package com.xhwl.centiotdata.pushtrigger.alarm.subscribe;

import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xhwl.centiotdata.pojo.constant.IVS1800Constant;
import com.xhwl.common.dto.cent.alarm.AlarmIntegrationConfigDTO;
import com.xhwl.centiotdata.pollingtrigger.ScheduleDispatcher;
import com.xhwl.centiotdata.service.integrateconfig.AlarmIntegrationConfig;
import com.xhwl.centiotdata.utils.ThreadPoolUtils;
import com.xhwl.common.dto.cent.alarm.haiwei1800.*;
import com.xhwl.common.dto.cent.alarm.haiwei3800.AlarmSnapshotListResult;
import com.xhwl.common.enums.ProductEnum;
import com.xhwl.common.utils.XMLUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.ListUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Slf4j
@Component
public class IVS1800Subscribe implements ScheduleDispatcher {

    @Autowired
    AlarmIntegrationConfig alarmIntegrationConfig;

    private static final List<AlarmIntegrationConfigDTO> integrationConfigList = new ArrayList<>();

    @Override
    public void doOneMinutesTask() {

    }

    @Override
    public void doTenMinutesTask () {
        ThreadPoolUtils.alarmExecutor.execute(this::getToken);
    }

    @Override
    public void doOneDayTask() {
        ThreadPoolUtils.alarmExecutor.execute(this::resetSubscribe);
    }

    @Override
    public void doOneHourTask() {

    }

    @EventListener
    public void listenIntegrationConfig(AlarmIntegrationConfigEvent event) {
        ThreadPoolUtils.alarmExecutor.execute(this::getToken);
    }

    public void resetSubscribe() {
        for (AlarmIntegrationConfigDTO configDTO : integrationConfigList) {
            try {
                if (!StringUtils.isEmpty(configDTO.getToken())) {
                    log.info("===== ivs1800 重新订阅  {}", configDTO);
                    alarmSubscribe(configDTO);
                    intelligenceSubscribe(configDTO);
                } else {
                    log.error("ivs1800 告警重新订阅失败, token 不存在 {}", configDTO);
                }
            }
            catch (Exception e) {
                log.error("ivs1800 告警重新订阅失败 {}", e.getMessage());
            }
        }
    }

    private void getToken() {
        syncConfig();
        for (AlarmIntegrationConfigDTO configDTO : integrationConfigList) {
            try {
                log.info("====== IVS 1800 开始 ===================: {}", configDTO);
                if (StringUtils.isEmpty(configDTO.getToken())) {
                    String token = login(configDTO);
                    if (!StringUtils.isEmpty(token)) {
                        configDTO.setToken(token);
                        log.info("IVS 1800 获取登录成功==============: {}", configDTO);
                        alarmSubscribe(configDTO);
                        intelligenceSubscribe(configDTO);
                    }
                } else {
                    keepAlive(configDTO);
                }
            }
            catch (Exception e) {
                log.error("ivs1800 订阅失败 {}", e.getMessage());
            }
        }

    }

    private static Boolean keepAlive(AlarmIntegrationConfigDTO configDTO) {
        if (StringUtils.isEmpty(configDTO.getIpAndPort())) {
            log.error("1800 配置为空: {}", configDTO);
            return false;
        }
        log.info("1800保活 {}", configDTO);
        String url = configDTO.getIpAndPort() + IVS1800Constant.KEEP_ALIVE_URL;
        if (StringUtils.isEmpty(configDTO.getToken())) {
            log.error("1800 token为空, 保活失败: {}", configDTO);
            return false;
        }
        String result = HttpUtil.createGet(url)
                .cookie("JSESSIONID=" + configDTO.getToken())
                .execute()
                .body();
        log.info("保活请求返回====================》{}", JSONObject.toJSONString(result));
        JSONObject object = JSONObject.parseObject(result);
        if (object.getInteger("resultCode") != 0) {
            configDTO.setToken(null);
            return false;
        }
        log.info("IVS 1800 保活成功 {}", configDTO);
        return true;
    }

    private static String login(AlarmIntegrationConfigDTO configDTO) {
        if (StringUtils.isEmpty(configDTO.getIpAndPort())) {
            log.error("1800 配置为空: {}", configDTO);
            return null;
        }
        log.info("1800登录 {}", configDTO);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("userName", configDTO.getLoginName());
        jsonObject.put("password", configDTO.getPassword());
        String url = configDTO.getIpAndPort() + IVS1800Constant.LOGIN_URL;

        HttpResponse response = HttpUtil.createPost(url)
                .body(jsonObject.toString())
                .execute();
        String body = response.body();
        String setCookieHeader = response.header("Set-Cookie");
        String JSESSIONID = null;
        if (Objects.nonNull(setCookieHeader)) {
            JSESSIONID = IVS1800Subscribe.getCookieToken(setCookieHeader);
            if (Objects.isNull(JSESSIONID)) {
                log.error("登录错误 cookies: {}", body);
                return null;
            }
            log.info("获取token成功 {}", JSESSIONID);
            return JSESSIONID;
        } else {
            log.error("登录错误 body: {}", body);
        }
        return null;
    }

    private void syncConfig() {
        List<AlarmIntegrationConfigDTO> list = alarmIntegrationConfig.getIntegrationProductConfig(
                null, ProductEnum.HUAWEI_IVS1800.getId());
        for (AlarmIntegrationConfigDTO i : list) {
            if (ObjectUtils.isEmpty(i)) {
                log.error("1800 告警集成配置为空，{}", i);
                continue;
            }
            for (AlarmIntegrationConfigDTO j : integrationConfigList) {
                if (Objects.nonNull(j.getToken()) && Objects.equals(j.getRowId(), i.getRowId())) {
                    i.setToken(j.getToken());
                }
            }
        }
        integrationConfigList.clear();
        integrationConfigList.addAll(list);
    }

    public static String getCookieToken(String setCookieHeader) {
        String JSESSIONID = null;
        if (!StringUtils.isEmpty(setCookieHeader)) {
            String[] cookies = setCookieHeader.split(";");
            for (String cookie : cookies) {
                List<String> splits = Arrays.asList(cookie.split("="));
                String cookieKey = Optional.ofNullable(splits.get(0)).map(i -> i.trim()).orElse(null);
                String cookieValue = Optional.ofNullable(splits.get(1)).map(i -> i.trim()).orElse(null);
                if (Objects.nonNull(cookieKey)
                        && Objects.nonNull(cookieValue)
                        && Objects.equals(cookieKey, "JSESSIONID")) {
                    JSESSIONID = cookieValue;
                    break;
                }
            }
        }
        return JSESSIONID;
    }

    public static void alarmSubscribe(AlarmIntegrationConfigDTO configDTO) {
        if (StringUtils.isEmpty(configDTO.getAlarmCallback())) {
            log.info("告警订阅地址为空，{}", configDTO);
            return;
        }

        // 订阅告警,订阅全部设备
        try {
            AlarmSubscribeContent alarmSubscribeContent = new AlarmSubscribeContent();
            AlarmSubscribe alarmSubscribe = new AlarmSubscribe();
            AlarmAddSubscribeList alarmAddSubscribeList = new AlarmAddSubscribeList();
            alarmSubscribe.setAddSubscribeList(alarmAddSubscribeList);
            alarmSubscribeContent.setSubscribe(alarmSubscribe);
            List<AlarmAddSubscribeListContent> addSubscribeListContents = new ArrayList<>();
            alarmAddSubscribeList.setSubscribeInfo(addSubscribeListContents);

            String xml = XMLUtil.convertToXml(alarmSubscribeContent);
            Pattern p = Pattern.compile("\\s*|\t|\r|\n");
            Matcher m = p.matcher(xml);
            String s = m.replaceAll("");
            HashMap<String, String> body = new HashMap<>();
            body.put("requestXML", s);
            log.info("1800 告警订阅请求体为====================》{}", JSONObject.toJSONString(body));

            //请求订阅
            String result = HttpUtil.createPost(configDTO.getIpAndPort() + IVS1800Constant.ALARM_SUBSCRIBE_URL)
                    .body(JSONObject.toJSONString(body))
                    .cookie("JSESSIONID=" + configDTO.getToken())
                    .execute()
                    .body();
            log.info("1800 告警订阅请求返回====================》{}", JSONObject.toJSONString(result));
            JSONObject object = JSONObject.parseObject(result);
            if (object.getInteger("resultCode") != 0) {
                configDTO.setToken(null);
                log.error("1800 告警设备订阅请求 失败");
                return;
            }
            log.info("1800 告警订阅请求成功");

            String alarmCallback = configDTO.getAlarmCallback()
                    .replace("{rowId}", configDTO.getRowId().toString());
            String result2 = HttpUtil.createPost(configDTO.getIpAndPort() + IVS1800Constant.REGEDIT_CALLBACK_URL)
                    .body(
                            JSONObject.toJSONString(new HashMap<String, Object>() {{
                                put("wsUri", alarmCallback);
                            }})
                    )
                    .cookie("JSESSIONID=" + configDTO.getToken())
                    .execute()
                    .body();
            log.info("ivs 1800 告警注册回调地址返回====================》{}", JSONObject.toJSONString(result2));
            JSONObject object2 = JSONObject.parseObject(result2);
            if (object2.getInteger("resultCode") != 0) {
                configDTO.setToken(null);
                log.error("ivs 1800 告警注册回调地址 失败");
                return;
            }
            log.info("ivs 1800 告警回调设置成功成功 {}", alarmCallback);
        } catch (Exception e) {
            configDTO.setToken(null);
            log.error("ivs 1800  告警订阅 失败: {}，{}", configDTO, e);
        }
    }

    public static List<CameraBriefInfo> getCameraList(AlarmIntegrationConfigDTO configDTO) {
        List<CameraBriefInfo> cameraList = new ArrayList<>();
        int fromIndex = 1;
        int toIndex = 1;
        HuaWei1800DeviceListResult allResult;
        try {
            log.info("当前  fromIndex：{}----toIndex:{}", fromIndex, toIndex);
            HuaWei1800DeviceListResult result = doGetCameraList(configDTO, fromIndex, toIndex);
            // 判断是否请求成功
            if (0 == result.getResultCode()) {
                // 一次性调完，保证设备中台同步时全量新增和全量修改
                int total = result.getCameraBriefInfos().getTotal();
                log.info("1800平台拉取设备列表个数:{}", total);

                allResult = doGetCameraList(configDTO, fromIndex, total);
                if (0 == allResult.getResultCode()
                        && allResult.getCameraBriefInfos().getCameraBriefInfoList().size() == total) {
                    // 将请求结果加入结果集
                    cameraList.addAll(allResult.getCameraBriefInfos().getCameraBriefInfoList());
                } else {
                    throw new RuntimeException("hw1800 get all devices fail," + result.getResultCode());
                }
            } else {
                throw new RuntimeException("hw1800 first pull devices fail," + result.getResultCode());
            }
        } catch (Exception e) {
            log.error("hw1800 getCameraList error: {}, {}, {}, exception: {}", HuaWei1800DeviceListResult.class, fromIndex, toIndex, e.getMessage());
            return Collections.emptyList();
        }
        // 必须全部拉取才进行同步
        log.info("项目 {} 1800平台设备个数：{}", configDTO.getProjectId(), cameraList.size());

        return cameraList;
    }

    public static HuaWei1800DeviceListResult doGetCameraList(AlarmIntegrationConfigDTO configDTO, int fromIndex, int toIndex) {
        String url = configDTO.getIpAndPort() + IVS1800Constant.DEVICE_LIST_URL;
        String body = HttpUtil.createGet(url)
                .cookie("JSESSIONID=" + configDTO.getToken())
                .form("deviceType", 2)
                .form("fromIndex", fromIndex)
                .form("toIndex", toIndex)
                .setConnectionTimeout(3000)
                .setReadTimeout(5000)
                .execute()
                .body();
        return JSON.parseObject(body, HuaWei1800DeviceListResult.class);
    }

    public static void intelligenceSubscribe(AlarmIntegrationConfigDTO configDTO) {
        if (StringUtils.isEmpty(configDTO.getAlarmCallback())) {
            log.info("1800 智能数据订阅地址为空，{}", configDTO);
            return;
        }

        // 订阅智能数据,订阅全部设备
        String intelligenceCallback = configDTO.getIntelligenceCallback()
                .replace("{rowId}", configDTO.getRowId().toString());

        // 查询已经订阅智能数据的地址
        List<IVS1800IntelligenceSubscribeQueryResult.Subscribe> subscribeList = new ArrayList<>();
        try {
            subscribeList = getExistintelligenceSubscribe(configDTO);
        } catch (Exception e) {
            log.error("ivs 1800 查询已经订阅智能数据的地址失败 {}", e.getMessage());
        }

        try {
            JSONObject obj = new JSONObject();
            JSONObject SubscribeListObject = new JSONObject();
            JSONArray SubscribeObject = new JSONArray();
            JSONObject Subscribe = new JSONObject();

            Subscribe.put("Title", "IVS1800IntelligenceSubscription");
            Subscribe.put("SubscribeDetail", "0");
            Subscribe.put("ResourceURI", "");
            Subscribe.put("CodeType", 0);
            Subscribe.put("ReceiveAddr", intelligenceCallback);
            Subscribe.put("ResultFeatureDeclare", 1);
            Subscribe.put("ResultImgType", 1);

            SubscribeObject.add(Subscribe);
            SubscribeListObject.put("SubscribeObject", SubscribeObject);
            obj.put("SubscribeListObject", SubscribeListObject);

            log.info("1800 智能订阅请求体为====================》{}", JSONObject.toJSONString(obj));
            String result = HttpRequest.post(configDTO.getIpAndPort() + IVS1800Constant.INTELLIGENCE_SUBSCRIBE_URL)
                    .cookie("JSESSIONID=" + configDTO.getToken())
                    .body(JSONObject.toJSONString(obj))
                    .execute()
                    .body();
            log.info("1800 智能订阅回调请求返回====================》{}", JSONObject.toJSONString(result));
            JSONObject object = JSONObject.parseObject(result);
            if (object.getInteger("resultCode") != 0) {
                configDTO.setToken(null);
                return;
            }
            log.info("1800 智能订阅成功 {}", intelligenceCallback);
        } catch (Exception e) {
            configDTO.setToken(null);
            log.error("1800 智能订阅失败 {}", e.getMessage());
        }

        // 删除之前的订阅，防止多次订阅
        try {
            if (!CollectionUtils.isEmpty(subscribeList)) {
                List<String> subscribeIDList = subscribeList.stream()
                        .filter(i -> {
                            if (Objects.equals(intelligenceCallback, i.getReceiveAddr())) {
                                log.info("1800智能数据已订阅重复id，{}, {}", i.getSubscribeID(), i.getReceiveAddr());
                                return true;
                            }
                            return false;
                        })
                        .map(IVS1800IntelligenceSubscribeQueryResult.Subscribe::getSubscribeID)
                        .collect(Collectors.toList());
                log.info("1800智能数据已订阅重复id，{}", subscribeIDList);

                // 删除相关订阅
                if (!CollectionUtils.isEmpty(subscribeIDList)) {
                    delIntelligenceSubscribe(configDTO, subscribeIDList);
                }
            } else {
                log.info("ivs 1800智能数据不存在已订阅重复id");
            }
        } catch (Exception e) {
            log.error("查询1800已经订阅智能数据的地址错误，{}", e.getMessage());
        }
    }

    public static List<IVS1800IntelligenceSubscribeQueryResult.Subscribe> getExistintelligenceSubscribe(
            AlarmIntegrationConfigDTO configDTO) {
        List<IVS1800IntelligenceSubscribeQueryResult.Subscribe> subscribeList = new ArrayList<>();
        String result = HttpRequest.get(configDTO.getIpAndPort() + IVS1800Constant.INTELLIGENCE_SUBSCRIBE_URL)
                .cookie("JSESSIONID=" + configDTO.getToken())
                .form("fromIndex", 1)
                .form("toIndex", 500)
                .execute()
                .body();
        IVS1800IntelligenceSubscribeQueryResult queryResult = JSONObject.parseObject(result, IVS1800IntelligenceSubscribeQueryResult.class);
        log.info("ivs800查询智能订阅 结果: {}", queryResult);
        if (Objects.equals(queryResult.getResultCode(), 0)) {
            subscribeList = queryResult.getSubscribeListObject().getSubscribeObject();
        }
        return subscribeList;
    }

    public static Boolean delIntelligenceSubscribe(AlarmIntegrationConfigDTO configDTO, List<String> subscribeIDList) {
        JSONObject obj = new JSONObject();
        JSONArray list = new JSONArray();
        obj.put("SubscribeIDList", list);
        for (String id : subscribeIDList) {
            JSONObject i = new JSONObject();
            i.put("SubscribeID", id);
            list.add(i);
        }
        log.error("ivs1800删除订阅参数: {}", obj);
        String result = HttpRequest.delete(configDTO.getIpAndPort() + IVS1800Constant.INTELLIGENCE_SUBSCRIBE_URL)
                .cookie("JSESSIONID=" + configDTO.getToken())
                .body(JSONObject.toJSONString(obj))
                .execute()
                .body();
        JSONObject res = JSONObject.parseObject(result);
        log.info("ivs1800删除订阅 结果: {}", res);
        if (Objects.equals(res.get("resultCode"), 0)) {
            return true;
        }
        return false;
    }

    public static AlarmSnapshotListResult getAlarmSnapshotList(AlarmIntegrationConfigDTO configDTO, Integer eventId) {
        Map<String, Object> hashMap = new HashMap<>();
        Map<String, Integer> alarmInfo = new HashMap<>();
        alarmInfo.put("alarmEventId", eventId);
        hashMap.put("alarmInfo", alarmInfo);
        String token = configDTO.getToken();
        String url = configDTO.getIpAndPort() + IVS1800Constant.ALARM_SNAPSHOT_LIST_URL;
        AlarmSnapshotListResult snapshotListResult = null;
        if (!StringUtils.isEmpty(token)) {
            log.info("1800获取告警图片 参数 : {}", hashMap);
            String picture = HttpUtil.createPost(url)
                    .body(JSONObject.toJSONString(hashMap))
                    .cookie("JSESSIONID=" + token)
                    .execute()
                    .body();
            log.info("1800告警图片结果: {}", picture);
            snapshotListResult = JSONObject.parseObject(picture, AlarmSnapshotListResult.class);
        }
        return snapshotListResult;
    }
}
